package com.zerone.pay.trade.service.impl;

import com.acooly.core.common.boot.Apps;
import com.acooly.core.common.exception.BusinessException;
import com.acooly.core.common.facade.SingleResult;
import com.acooly.core.utils.Ids;
import com.acooly.core.utils.Money;
import com.acooly.core.utils.enums.ResultStatus;
import com.acooly.module.appservice.AppService;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayTradeCreateRequest;
import com.alipay.api.response.AlipayTradeCreateResponse;
import com.github.wxpay.sdk.WXPay;
import com.google.gson.Gson;
import com.zerone.facade.merchant.api.MerchantQueryFacade;
import com.zerone.facade.merchant.info.MerchantInfo;
import com.zerone.facade.merchant.order.MerchantQueryOrder;
import com.zerone.pay.trade.repository.dao.TradeDao;
import com.zerone.pay.trade.repository.entity.Trade;
import com.zerone.pay.trade.enums.PayMethodEnum;
import com.zerone.pay.trade.enums.TradeStatusEnum;
import com.zerone.pay.trade.service.TradeService;
import com.zerone.pay.trade.service.order.AliTradeStatusEnum;
import com.zerone.pay.trade.service.order.TradeCreateOrder;
import com.zerone.pay.trade.service.order.TradePayNotifyOrder;
import com.zerone.payment.account.facade.api.AccountUnilateralFacade;
import com.zerone.payment.account.facade.enums.CurrencyEnum;
import com.zerone.payment.account.facade.enums.TransCodeEnum;
import com.zerone.payment.account.facade.info.UnilateralTransInfo;
import com.zerone.payment.account.facade.order.DepositAccountOrder;
import com.zerone.payment.common.facade.enums.TransTypeEnum;
import com.zerone.payment.common.facade.result.PaymentResult;
import com.zerone.payment.common.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 木鱼 muyu@yiji.com
 * @version 2017/4/19
 */
@Service
public class TradeServiceImpl implements TradeService {


  protected static final Logger logger = LoggerFactory.getLogger(TradeServiceImpl.class);

  @Autowired
  private AlipayClient alipayClient;

  @Autowired
  private WXPay wXpay;

  @Autowired
  private WXPay wXpayUseSandBox;


  @Autowired
  private TradeDao tradeDao;


  @Autowired
  private MerchantQueryFacade merchantQueryFacade;


  @Autowired
  private AccountUnilateralFacade accountUnilateralFacade;

  /**
   * 创建交易订单
   *
   * @param order
   * @return
   */
  @AppService
  @Override
  @Transactional
  public String create(TradeCreateOrder order) throws Exception {

    Trade trade = buildTrade(order);
    String tradeNo = null;
    if (order.getPayMethod().equals(PayMethodEnum.ali_code.code())) {
      AlipayTradeCreateResponse response = aliPay(order, trade);
      tradeNo = response.getTradeNo();
    } else {

      Map<String, String> data = buildWechatPayOrder(order, trade);
      Map<String, String> resp = wXpay.unifiedOrder(data);
      logger.info("微信统一下单入参 data={},出参resp={}", data, resp);
      if ("SUCCESS".equals(resp.get("return_code")) && "SUCCESS".equals(resp.get("result_code"))) {
        tradeNo = resp.get("prepay_id");
      }
      trade.setOutTradeNo(tradeNo);
    }
    return tradeNo;
  }

  private Map<String, String> buildWechatPayOrder(TradeCreateOrder order, Trade trade) {
    Map<String, String> data = new HashMap<String, String>();
    data.put("body", trade.getBody());
    data.put("out_trade_no", trade.getOutOrderNo());
    data.put("device_info", "none");
    data.put("total_fee", String.valueOf(trade.getTradeAmount()));
    data.put("spbill_create_ip", order.getIp());
    data.put("notify_url",
        Apps.getEnvironment().getProperty("pay.domain.name") + "notify/wechatPay");
    data.put("trade_type", "JSAPI"); // 此处指定为扫码支付
    data.put("openid", order.getUserId());
    return data;
  }

  private AlipayTradeCreateResponse aliPay(TradeCreateOrder order, Trade trade)
      throws AlipayApiException {
    BizContent bizContent = new BizContent();
    bizContent.setOut_trade_no(trade.getOutOrderNo());
    bizContent.setSubject("xxx门店当面付扫码消费");
    bizContent.setTotal_amount(Money.cent(trade.getTradeAmount()).toString());
    bizContent.setBody("一码支付");
    // FIXME 填写商户信息
    bizContent.setStore_id("test_store_id");
    String timeoutExpress = "120m";
    bizContent.setTimeout_express(timeoutExpress);
    bizContent.setBuyer_id(order.getUserId());

    // 创建扫码支付请求builder，设置请求参数
    AlipayTradeCreateRequest alipayTradeCreateRequest = new AlipayTradeCreateRequest();
    alipayTradeCreateRequest.setBizContent(new Gson().toJson(bizContent));
    alipayTradeCreateRequest
        .setNotifyUrl(Apps.getEnvironment().getProperty("pay.domain.name") + "notify/alipay");
    AlipayTradeCreateResponse response = alipayClient.execute(alipayTradeCreateRequest);
    logger.info("返回结果：outOrderNo={},tradeNo={}", response.getOutTradeNo(), response.getTradeNo());
    if (!response.isSuccess()) {
      logger.error("创建交易失败order={},result={}", alipayTradeCreateRequest, response);
      throw new BusinessException("创建交易失败order=" + alipayTradeCreateRequest);
    }
    return response;
  }

  private Trade buildTrade(TradeCreateOrder order) {
    Trade trade = new Trade();
    trade.setMerchantId(order.getPartnerId());
    trade.setPayMethod(order.getPayMethod());
    trade.setOutOrderNo(order.getOutOrderNo());

    MerchantQueryOrder merchantQueryOrder = new MerchantQueryOrder();
    merchantQueryOrder.setPartnerId(order.getPartnerId());
    merchantQueryOrder.setGid(order.getGid());
    merchantQueryOrder.setMerchantId(order.getPartnerId());
    SingleResult<MerchantInfo> singleResult =
        merchantQueryFacade.queryByMerchantId(merchantQueryOrder);
    if (singleResult.getStatus() != ResultStatus.success) {
      logger.info("查询商户信息失败 singleResult={}", singleResult);
      throw new BusinessException(singleResult.getDetail());
    }
    trade.setMerchantName(singleResult.getDto().getMerchantName());
    trade.setMerchantAccountNo(singleResult.getDto().getAccountNo());
    // FIXME 未完
    // trade.setNotifyUrl();
    // trade.setRate(singleResult.getDto().get);

    MerchantQueryOrder merchantAgentQueryOrder = new MerchantQueryOrder();
    merchantAgentQueryOrder.setPartnerId(order.getPartnerId());
    merchantAgentQueryOrder.setGid(order.getGid());
    merchantAgentQueryOrder.setMerchantId(singleResult.getDto().getParentMerchantId());
    SingleResult<MerchantInfo> agentMerchantInfoResult =
        merchantQueryFacade.queryByMerchantId(merchantAgentQueryOrder);
    if (agentMerchantInfoResult.getStatus() != ResultStatus.success) {
      logger.info("查询代理商户信息失败 singleResult={}", agentMerchantInfoResult);
      throw new BusinessException(agentMerchantInfoResult.getDetail());
    }

    trade.setAgentId(agentMerchantInfoResult.getDto().getMerchantId());
    trade.setAgentName(agentMerchantInfoResult.getDto().getMerchantName());

    trade.setBody("一码支付");
    trade.setBuyerId(order.getUserId());
    trade.setChannel(order.getPayMethod());
    trade.setTradeNo(order.getOutOrderNo());
    trade.setExpire("120m");

    trade.setSubject(trade.getMerchantName() + ":一码付");
    trade.setTradeAmount(new Money(order.getAmount()).getCent());
    trade.setTradeStatus(TradeStatusEnum.processing.getCode());
    trade.setCreateTime(new Date());
    return trade;
  }

  @Override
  @Transactional
  @AppService
  public void payNotify(TradePayNotifyOrder tradePayNotifyOrder) {
    Trade trade = tradeDao.findUniqu("tradeNo",tradePayNotifyOrder.getOutTradeNo());
    if (trade != null && StringUtil.equals(trade.getTradeStatus(),TradeStatusEnum.processing.getCode())) {
      if (tradePayNotifyOrder.getAliTradeStatus() == AliTradeStatusEnum.TRADE_FINISHED
          || tradePayNotifyOrder.getAliTradeStatus() == AliTradeStatusEnum.TRADE_SUCCESS) {
        trade.setTradeStatus(TradeStatusEnum.success.getCode());
        DepositAccountOrder depositAccountOrder = new DepositAccountOrder();
        depositAccountOrder.setGid(tradePayNotifyOrder.getGid());
        depositAccountOrder.setPartnerId(tradePayNotifyOrder.getPartnerId());
        depositAccountOrder.setAccountNo(trade.getMerchantAccountNo());
        depositAccountOrder.setCurrency(CurrencyEnum.CNY);
        //FIXME 先上账到商户账户中
        depositAccountOrder.setTransAmount(Money.cent(trade.getTradeAmount()));
        depositAccountOrder.setTransCode(TransCodeEnum.DEPOSIT_ACCOUNT);
        depositAccountOrder.setBizOrderNo(trade.getTradeNo());
        depositAccountOrder.setMerchantOrderNo(trade.getOutOrderNo());
        depositAccountOrder.setMemo(trade.getDescription());
        depositAccountOrder.setTransType(TransTypeEnum.ALI_PAY_DEPOSIT);
        //FIXME 需要修改
        depositAccountOrder.setSettleBizNo(Ids.getDid());
        depositAccountOrder.setSettleDate(new Date());
        //FIXME 备付金账号
        depositAccountOrder.setSettleChannelApi("123");
        PaymentResult<UnilateralTransInfo> paymentResult =accountUnilateralFacade.deposit(depositAccountOrder);
        if(paymentResult.isFail()){
          logger.info("充值失败result={}",paymentResult);
          throw new BusinessException(paymentResult.getResultMessage());
        }
      } else if (tradePayNotifyOrder.getAliTradeStatus() == AliTradeStatusEnum.TRADE_CLOSED) {
        trade.setTradeStatus(TradeStatusEnum.fail.getCode());
      }
      trade.setUpdateTime(new Date());
      tradeDao.save(trade);
    }
  }
}
